package com.zshy.base.core.utils;

import com.zshy.base.core.context.BaseContext;
import com.zshy.base.core.contract.constant.ContextConstants;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 异常工具类
 *
 * @author zhouhengzhe
 */
@Slf4j
@UtilityClass
public class ExceptionKit {
    /**
     * 获取项目中异常堆栈信息
     *
     * @param e 异常的实例
     * @return 返回异常在项目中发生的堆栈信息，如果无法获取则返回异常的本地化消息
     */
    public String getProjectStackTraces(Throwable e) {
        // 创建一个列表用于存储异常堆栈信息
        List<StackTraceElement> stackTraceElements = new ArrayList<>(e.getStackTrace().length);
        // 将异常的堆栈信息添加到列表中
        Collections.addAll(stackTraceElements, e.getStackTrace());
        // 调用获取项目中异常堆栈信息的辅助方法
        String projectStackTraces = getProjectStackTracesFromElements(stackTraceElements);
        // 如果获取到了项目中异常堆栈信息，则返回该信息
        if (projectStackTraces != null) {
            return projectStackTraces;
        }
        // 如果无法获取项目中异常堆栈信息，则返回异常的本地化消息
        return e.getLocalizedMessage();
    }

    /**
     * 获取项目中异常堆栈信息
     *
     * @param stackTraceElements 异常堆栈信息列表
     * @return 返回项目中异常堆栈信息字符串，如果传入的列表为空或者获取不到项目包名则返回null
     */
    public String getProjectStackTracesFromElements(List<StackTraceElement> stackTraceElements) {
        if (stackTraceElements == null) {
            return null;
        }
        String projectPackage = BaseContext.get(ContextConstants.PROJECT_PACKAGE);
        if (projectPackage != null) {
            StringBuilder stringBuilder = new StringBuilder();
            for (int i = 0; i < stackTraceElements.size(); i++) {
                StackTraceElement s = stackTraceElements.get(i);
                String fileName = s.getFileName();
                int lineNumber = s.getLineNumber();
                // 忽略文件名或行号为空的堆栈信息
                if (fileName == null || lineNumber == -1) {
                    continue;
                }
                String className = s.getClassName();
                // 判断是否属于项目中的类
                boolean isProjectClass = className.startsWith(projectPackage);
                if (i == 0 && !isProjectClass) {
                    // 如果是第一个元素且不属于项目中的类，则添加文件名和行号，并在末尾添加"..."
                    stringBuilder.append(fileName).append("(").append(lineNumber).append(") ...");
                } else if (isProjectClass) {
                    // 如果是项目中的类，则添加文件名和行号
                    if (!stringBuilder.isEmpty()) {
                        // 如果字符串构建器已有内容，则添加分号和空格
                        stringBuilder.append("; ");
                    }
                    stringBuilder.append(fileName).append("(").append(lineNumber).append(")");
                }
            }
            // 去除末尾的 "; "（如果存在）并替换 "...;" 为 "..."
            // 去除末尾的 "; "（如果存在）
            int length = stringBuilder.length();
            if (length > 0 && stringBuilder.substring(length - 2).equals("; ")) {
                stringBuilder.setLength(length - 2);
            }
            // 替换 "...;" 为 "..."
            if (stringBuilder.toString().endsWith("...;")) {
                stringBuilder.setLength(stringBuilder.length() - 1);
            }
            // 返回最终的字符串结果
            return stringBuilder.toString();
        }
        return null;
    }
}
